import os

import pygame
from pygame.locals import *

import data, gradients

hud = None

class Struct(object):
    def __init__(self, **kw):
        self.__dict__.update(kw)

THEME = Struct(
    playerhealth = Struct(
        bar_color_full = Color('green'),
        bar_color_empty = Color('red'),
        bar_color_value = Color('darkred'),
        border_color = Color('grey'),
        bar_height = 15,
        bar_width = 200,
        border_width = 2,
        font_file = 'UniversElse-Bold.ttf',
        font_size = 12,
        text_color = Color('white'),
    ),
    weaponstatus = Struct(
        bar_color_none = Color(55,88,55),
        bar_color_ready = Color('darkgreen'),
        bar_color_strike = Color('red'),
        bar_color_cooldown = Color('red'),
        bar_color_empty = Color(55,88,55),
        border_color = Color('grey'),
        bar_height = 15,
        bar_width = 200,
        border_width = 2,
        font_file = 'UniversElse-Bold.ttf',
        font_size = 12,
        text_color = Color('white'),
    ),
)

class HUD(object):
    
    def __init__(self, position=(10,10)):
        self.sprites = []
        self.sprites_dict = {}
        self.position = position
        
        global hud
        hud = self
    
    def add(self, name, sprite):
        sprites = self.sprites
        sprites_dict = self.sprites_dict
        if sprite in sprites:
            return
        sprites.append(sprite)
        sprites_dict[name] = sprite
    
    def update(self, name, *args):
        self.sprites_dict[name].update(*args)
    
    def draw(self, surf):
        x,y = self.position
        for sprite in self.sprites:
            surf.blit(sprite.image, (x,y))
            y += sprite.rect.height + 3

class PlayerHealth(pygame.sprite.Sprite):
    
    def __init__(self, value):
        super(PlayerHealth, self).__init__()
        theme = THEME.playerhealth
        self.image = pygame.surface.Surface((theme.bar_width, theme.bar_height))
        self.rect = self.image.get_rect()
        
        self.font = pygame.font.Font(
            data.filepath(os.path.join('font',theme.font_file)), theme.font_size)
        
        self.full = value
        self.value = value
        self._render()
    
    def update(self, value):
        if value != self.value:
            self.value = value
            self._render()
    
    def _render(self):
        theme = THEME.playerhealth
        # draw the gradient
        bw = theme.border_width
        start_point = (0,0)
        end_point = (theme.bar_width, theme.bar_height)
        gradients.draw_gradient(
            self.image,
            start_point, end_point,
            theme.bar_color_empty, theme.bar_color_full,
        )
        # draw lost health gauge
        if self.value < self.full:
            left = float(theme.bar_width) * float(self.value) / float(self.full)
            fill_rect = (left, 0, theme.bar_width, theme.bar_height)
            self.image.fill(theme.bar_color_value, fill_rect)
        # draw text
        text = '%d / %d' % (self.value,self.full)
        label = self.font.render(text, True, theme.text_color)
        label_rect = label.get_rect(center=self.image.get_rect().center)
        self.image.blit(label, label_rect)
        # draw border
        pygame.draw.rect(self.image,
            theme.border_color, self.image.get_rect(), theme.border_width)

class WeaponStatus(pygame.sprite.Sprite):
    
    def __init__(self, weapon=None):
        super(WeaponStatus, self).__init__()
        theme = THEME.weaponstatus
        self.image = pygame.surface.Surface((theme.bar_width, theme.bar_height))
        self.rect = self.image.get_rect()
        
        self.font = pygame.font.Font(
            data.filepath(os.path.join('font',theme.font_file)), theme.font_size)
        
        self.weapon = -1
        self.image_text = None
        self.images = {
            None : self.image.copy(),
            'ready' : self.image.copy(),
            'strike' : self.image.copy(),
            'cooldown' : self.image.copy(),
            'empty' : self.image.copy(),
        }
        self.images[None].fill(theme.bar_color_none)
        self.images['ready'].fill(theme.bar_color_ready)
        self.images['strike'].fill(theme.bar_color_strike)
        self.images['cooldown'].fill(theme.bar_color_cooldown)
        self.images['empty'].fill(theme.bar_color_empty)
        
        self.text = None
        self.state = None
        self.update(weapon)
    
    def update(self, weapon):
        theme = THEME.weaponstatus
        dirty = False
        if self.weapon is not weapon:
            self.weapon = weapon
            dirty = True
        if weapon is None:
            if dirty:
                self.text = 'No weapon'
                self.state = None
                # set background
                self.image.blit(self.images[None], (0,0))
                # render new text
                self.image_text = self.font.render(self.text, True, theme.text_color)
                rect = self.image_text.get_rect()
                # blit text
                self_rect = self.image.get_rect()
                rect.center = self_rect.center
                self.image.blit(self.image_text, rect)
                # draw border
                pygame.draw.rect(self.image,
                    theme.border_color, self_rect, theme.border_width)
        else:
            if (dirty or 
                    weapon.state != self.state or 
                    weapon.ammo != self.ammo or
                    weapon.state in ('strike','cooldown')
                ):
                self.state = weapon.state
                self.ammo = weapon.ammo
                # render new state
                self.image.blit(self.images[self.state], (0,0))
                ## TO DO: render gauge
                if weapon.state == 'ready':
                    pass
                elif weapon.state == 'strike':
                    attack = weapon.current_attack
                    percent = 1 - float(attack._speed) / float(attack.speed)
                    left = self.rect.width * percent
                    self.image.blit(self.images['ready'], (left,0))
                elif weapon.state == 'cooldown':
                    attack = weapon.current_attack
                    percent = float(attack._cooldown) / float(attack.cooldown)
                    left = self.rect.width * percent
                    self.image.blit(self.images['ready'], (left,0))
                elif weapon.state == 'empty':
                    pass
                # render new text
                if weapon.ammo is not None:
                    self.text = '%s %d ammo' % (weapon.name,weapon.ammo)
                else:
                    self.text = '%s unlimited' % (weapon.name,)
                self.image_text = self.font.render(self.text, True, theme.text_color)
                rect = self.image_text.get_rect()
                # blit text
                self_rect = self.image.get_rect()
                rect.center = self_rect.center
                self.image.blit(self.image_text, rect)
                self.image.blit(self.image_text, rect)
                # draw border
                pygame.draw.rect(self.image,
                    theme.border_color, self_rect, theme.border_width)
